/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.easoft.code.pos.data.dao;

import com.easoft.code.pos.data.exception.CoreDataLayerException;
import com.easoft.code.pos.data.util.QueryParameter;
import com.easoft.code.pos.util.Valores;
import java.io.Serializable;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.PropertyValueException;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.transform.Transformers;

/**
 *
 * @author Eliu
 */
public class GenericDao {

    private static final Logger logger = Logger.getLogger(GenericDao.class);
    private static SessionFactory sessionFactory;
    private static GenericDao me;

    public static GenericDao getMe() {
        if (me == null) {
            me = new GenericDao();
        }

        return new GenericDao();
    }

    static {
        try {
            AnnotationConfiguration config = new AnnotationConfiguration();
            config.setProperty("hibernate.connection.url", Valores.getConfigValue(Valores.DB_URL));
            config.setProperty("hibernate.connection.user", Valores.getConfigValue(Valores.DB_USER));
            config.setProperty("hibernate.connection.password", Valores.getConfigValue(Valores.DB_PASSWORD));
            sessionFactory = config.configure().buildSessionFactory();
        } catch (HibernateException e) {
            e.printStackTrace(System.err);
        }
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /**
     *
     * @param sql
     * @param params
     * @param entidad
     * @param unique
     * @param noReturn
     * @return
     * @throws CoreDataLayerException
     */
    public Object doSQL(String sql, QueryParameter[] params, Class entidad, boolean unique, boolean noReturn) throws CoreDataLayerException {
        try {
            sessionFactory.getCurrentSession().beginTransaction();
            Query query = sessionFactory.getCurrentSession().createSQLQuery(sql);
            for (QueryParameter qp : params) {
                query.setParameter(qp.getName(), qp.getValue());
            }
            Object r;
            if (noReturn) {
                r = query.executeUpdate();
            } else if (unique) {
                r = entidad.cast(query.uniqueResult());
            } else {
                r = query.setResultTransformer(Transformers.aliasToBean(entidad)).list();
            }
            sessionFactory.getCurrentSession().getTransaction().commit();
            return r;
        } catch (HibernateException e) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            logger.error(e);
            throw new CoreDataLayerException("Error de capa de datos!", e);
        }

    }

    /**
     *
     * @param jpql
     * @param params
     * @param entidad
     * @param unique
     * @return
     * @throws CoreDataLayerException
     */
    public Object doJQL(String jpql, QueryParameter[] params, Class entidad, boolean unique) throws CoreDataLayerException {
        try {
            sessionFactory.getCurrentSession().beginTransaction();
            Query q = sessionFactory.getCurrentSession().createQuery(jpql);
            for (QueryParameter r : params) {
                q.setParameter(r.getName(), r.getValue());
            }
            Object r;
            if (unique) {
                r = q.uniqueResult();
                r = r != null ? entidad.cast(r) : null;
            } else {
                r = q.list();
            }
            sessionFactory.getCurrentSession().getTransaction().commit();

            return r;

        } catch (HibernateException e) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            throw new CoreDataLayerException("Error de capda de datos", e);
        }
    }

    /**
     *
     * @param namedQuery
     * @param params
     * @param entidad
     * @param unique
     * @return
     * @throws CoreDataLayerException
     */
    public Object doNamedQuery(String namedQuery, QueryParameter[] params, Class entidad, boolean unique) throws CoreDataLayerException {
        try {
            sessionFactory.getCurrentSession().beginTransaction();
            Query q = sessionFactory.getCurrentSession().getNamedQuery(namedQuery);

            for (QueryParameter p : params) {
                q.setParameter(p.getName(), p.getValue());
            }
            Object r;
            if (unique) {
                r = entidad.cast(q.uniqueResult());
            } else {
                r = q.list();
            }
            sessionFactory.getCurrentSession().getTransaction().commit();

            return r;

        } catch (HibernateException e) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            throw new CoreDataLayerException("Error de capda de datos", e);
        }
    }

    /**
     *
     * @param o
     * @return
     * @throws CoreDataLayerException
     */
    public Object save(Object o) throws CoreDataLayerException {
        try {
            if (o instanceof ComposeEntity) {
                if (!((ComposeEntity) o).getForeingEntities().isEmpty()) {
                    for (Object e : ((ComposeEntity) o).getForeingEntities()) {
                        this.save(e);
                    }
                }
            }
            sessionFactory.getCurrentSession().beginTransaction();
            Serializable r = sessionFactory.getCurrentSession().save(o);
            sessionFactory.getCurrentSession().getTransaction().commit();
            return r;
        } catch (HibernateException e) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            if (e instanceof PropertyValueException) {
                throw new CoreDataLayerException("Uno o varios campos son requeridos!", e);
            }
            throw new CoreDataLayerException("Error de capda de datos", e);
        }
    }

    /**
     *
     * @param o
     * @throws CoreDataLayerException
     */
    public void update(Object o) throws CoreDataLayerException {
        try {
            sessionFactory.getCurrentSession().beginTransaction();
            sessionFactory.getCurrentSession().update(o);
            sessionFactory.getCurrentSession().getTransaction().commit();
        } catch (HibernateException e) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            throw new CoreDataLayerException("Error de capda de datos", e);
        }
    }

    /**
     *
     * @param o
     * @throws CoreDataLayerException
     */
    public void remove(Object o) throws CoreDataLayerException {
        try {
            sessionFactory.getCurrentSession().beginTransaction();
            sessionFactory.getCurrentSession().delete(o);
            sessionFactory.getCurrentSession().getTransaction().commit();
        } catch (Exception e) {
            sessionFactory.getCurrentSession().getTransaction().rollback();
            throw new CoreDataLayerException("Error de capda de datos", e);
        }
    }
}
